/*
 * FindReplacePanel
 * Copyright (C) 2011, Aleksey Nikiforov
 *
 * This file is part of FindReplacePanel.
 *
 * FindReplacePanel is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FindReplacePanel is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package simplex3d.console.findreplace;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import javax.swing.DefaultComboBoxModel;


/**
 *
 * @author Aleksey Nikiforov (lex)
 */
class PrefsComboBoxModel extends DefaultComboBoxModel {
    private String key;
    private Preferences prefs;
    private ArrayList<String> history;
    private int maxHistoryEntries = 25;

    @SuppressWarnings("unchecked")
    public PrefsComboBoxModel(Preferences prefs, String key) {
        this(getStringList(prefs, key));

        this.key = key;
        this.prefs = prefs;
    }

    private PrefsComboBoxModel(ArrayList<String> items) {
        super(items.toArray());
        this.history = items;
    }

    public void reloadItems() {
        int oldSize = history.size();
        history.clear();
        fireIntervalRemoved(this, 0, oldSize);

        try {
            prefs.sync();
        } catch (BackingStoreException ex) {
            // Do nothing.
        }

        history.addAll(getStringList(prefs, key));
        fireIntervalAdded(this, 0, history.size());
    }

    public void update() {
        String selected = (String) this.getSelectedItem();

        if (selected.length() > 0 && maxHistoryEntries > 0) {
            // Update the model.
            int index = getIndexOf(selected);
            if (index > 0) {
                removeElementAt(index);
            }
            if (index != 0) {
                insertElementAt(selected, 0);
                setSelectedItem(selected);
            }
        }

        while (getSize() > maxHistoryEntries) {
            removeElementAt(maxHistoryEntries);
        }

        // Convert items into byte array.
        String[] items = new String[getSize()];
        for (int i = 0; i < getSize(); i++) {
            items[i] = (String) getElementAt(i);
        }

        putStringArray(prefs, key, items);

        try {
            prefs.flush();
        } catch (BackingStoreException ex) {
            // Do nothing.
        }
    }

    public int getMaxHistoryEntries() {
        return maxHistoryEntries;
    }

    public void setMaxHistoryEntries(int maxHistoryEntries) {
        this.maxHistoryEntries = maxHistoryEntries;
    }


    private static void putStringArray(Preferences preferences, String key, String[] items) {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        try {
            ObjectOutputStream out = new ObjectOutputStream(bytes);
            out.writeObject(items);
            out.close();
        } catch (IOException ex) {
            throw new AssertionError();
        }

        // Persiste items as byte array.
        preferences.putByteArray(key, bytes.toByteArray());
    }

    private static String[] getStringArray(Preferences preferences, String key) {
        byte[] bytes = preferences.getByteArray(key, null);
        if (bytes == null) return new String[0];

        try {
            ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
            String modelArray[] = (String[]) in.readObject();
            in.close();
            return modelArray;
        } catch (ClassNotFoundException ex) {
            throw new AssertionError();
        } catch (IOException ex) {
            throw new AssertionError();
        }
    }

    @SuppressWarnings("unchecked")
    private static ArrayList<String> getStringList(Preferences preferences, String key) {
        String[] arr = getStringArray(preferences, key);
        ArrayList<String> list = new ArrayList(arr.length);
        list.addAll(Arrays.asList(arr));
        return list;
    }
}
